import { UpOutlined, DownOutlined } from '@ant-design/icons';
import { InbizIcon, useEvents } from '@inbiz/utils';
import { useInbizData } from '@inbiz/hooks';
import { Empty, TreeSelect as AntdTreeSelect } from 'antd';
import {
  forwardRef,
  Ref,
  useCallback,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import api from '../../api';
import type { IProps } from '../../index';
import { getTreeDatas, queryTreeParentIdDatas } from '../../services';
import './style.less';
import { TextWidget } from '@inbiz/react';
import { useUpdateEffect } from 'ahooks';
import {
  formatTreeData,
  getFieldKey,
  updateTreeData,
  findTreeNode,
  findTreeNodes,
  ITreeData,
  treeDataToArray,
  treeDataLevelFormat,
  findTreeParents,
} from '../../../../../Tree/preview/web/utils';
import { LegacyDataNode } from 'rc-tree-select/lib/TreeSelect';

type IRef = Ref<ReturnType<typeof api>>;

const { SHOW_ALL } = AntdTreeSelect;

const TreeSelect = forwardRef((props: IProps, ref: IRef) => {
  const {
    showIcon,
    multiple,
    prefixCls = 'inbiz-TreeSelect',
    config,
    inbiz,
    callBackEvents,
    businessData,
    sourceModel,
    onChange,
    sourcetype = 'model',
    value: oldValue,
    panelHeight = 0,
    expandNode,
    emit,
    title,
    disabled,
    readOnly,
    placeholder,
    controlId,
    viewMode,
    ...otherProps
  } = props;
  // 静态数据
  const { appId, treeCheckStrictly, IconsSettings, fieldRelation, sourceTypeNum, allowClear } =
    useMemo(() => {
      return {
        appId: inbiz.appInfo.appId,
        treeCheckStrictly: props.multiple,
        IconsSettings: config.IconsSettings,
        fieldRelation: config.fieldRelation,
        sourceTypeNum: 1,
        allowClear: true,
      };
    }, [config, props.multiple]);

  const [
    showTreeNameKey,
    treeNodeId,
    treeShowNodeId,
    treeNodeParentId,
    treeShowNodeParentId,
    rootId,
  ] = useMemo(() => {
    return [
      getFieldKey(fieldRelation['label'], 1),
      getFieldKey(fieldRelation['id']),
      getFieldKey(fieldRelation['id'], 1),
      getFieldKey(fieldRelation['parentId']),
      getFieldKey(fieldRelation['parentId'], 1),
      fieldRelation['rootId'] || 0,
    ] as const;
  }, [fieldRelation]);

  const [expandedKeys, $expandedKeys] = useState<string[]>([]);

  const [configEvents] = useEvents(callBackEvents, emit);
  const [dropDownOpen, $dropDownOpen] = useState(false);

  // treeData的最新数据，只用于数据查找，不参与任何业务逻辑
  const treeDataRef = useRef<ITreeData>();
  // treeData的数组平铺结构， 只用于value变更的时候判断是否加载不存在的节点
  const treeListRef = useRef<ITreeData>([]);
  const {
    data: treeData,
    mutate: $treeData,
    runAsync,
  } = useInbizData(
    () => {
      if (sourcetype === 'model') {
        return {
          service: ({
            appId,
            ...other
          }: {
            appId: string;
            sourceKey: string;
            value?: string | number;
            parentId?: string | number;
            sourceType: 1;
            id?: string | number;
          }) => {
            return other?.sourceKey ? getTreeDatas(appId, other) : Promise.resolve([]);
          },
        };
      } else {
        if (typeof sourceModel === 'object') {
          return sourceModel;
        } else {
          return { modelkey: sourceModel! };
        }
      }
    },
    {
      formatResult: ({
        data,
        lastData,
        params,
      }: {
        data: { Data: any[]; Rows?: [] };
        lastData: ITreeData;
        params: { key?: string };
      }): ITreeData => {
        if (!lastData?.length) {
          return formatTreeData({
            data: data?.Data || data?.Rows,
            key: treeShowNodeId,
            title: showTreeNameKey,
            childrenKey: 'child',
            treeNodeId: [treeNodeId, treeShowNodeId],
            treeNodeParentId: [treeNodeParentId, treeShowNodeParentId],
            format: (data) => {
              data.key = data?.key?.toString();
              data.value = data?.key;
            },
          }) as ITreeData;
        } else {
          const tree = formatTreeData({
            data:
              (sourcetype === 'model'
                ? data?.Data?.[0]?.child
                : Array.isArray(data.Rows)
                  ? data?.Rows
                  : [data?.Rows]) || [],
            key: treeShowNodeId,
            title: showTreeNameKey,
            childrenKey: 'child',
            treeNodeId: [treeNodeId, treeShowNodeId],
            treeNodeParentId: [treeNodeParentId, treeShowNodeParentId],
            format: (data) => {
              data.key = data?.key?.toString();
              data.value = data?.key;
            },
          });
          return updateTreeData({
            type: 'add',
            keyValue: params.key! as string,
            treeData: lastData,
            data: tree!,
          });
        }
      },
      initialData: [],
      configEvents,
    },
  );
  useEffect(() => {
    treeDataRef.current = treeData;
    treeListRef.current = treeDataToArray(treeData);
  }, [treeData]);
  // 请求数据的公共方法
  const getData = async (params: { key?: string }) => {
    if (!props.sourceModel && !configEvents.current.onRequest) {
      return;
    }
    let data = {};
    if (sourcetype === 'model') {
      data = {
        sourceKey: sourceModel!,
        sourceType: sourceTypeNum,
        id: treeNodeId,
        parentId: treeNodeParentId,
        key: params.key,
        appId,
      };
    } else {
      if (typeof sourceModel === 'string') {
        data = {
          appId,
          key: sourceModel,
          iConditions: params,
        };
      } else {
        data = params;
      }
    }
    return runAsync(data).then(
      (res: any) => {
        emit?.('onSuccess', res);
      },
      (error: any) => {
        emit?.('onError', error);
      },
    );
  };

  // 加载远端数据, 暂时只支持模型数据
  const loadOriginData = useCallback(
    async (key: string | string[]) => {
      if (sourcetype == 'model') {
        const pathArr: { path: string }[] = await queryTreeParentIdDatas(appId, {
          sourceKey: sourceModel!,
          sourceType: sourceTypeNum,
          id: treeNodeId,
          parentId: treeNodeParentId,
          values: Array.isArray(key) ? key.join(',') : key,
        });
        if (!pathArr?.length) {
          return Promise.reject('不存在远端数据');
        }
        for (const { path } of pathArr) {
          if (!path) {
            return Promise.reject('不存在远端数据');
          }
          // 最后一个节点不需要额外请求在上一个节点的child中, 如果是跟节点时还是需要请求
          const treeKeys = path.includes('/') ? path.split('/').slice(0, -1) : ([path] as string[]);
          // 在本地存在的节点,最后一个链条的节点
          const thereNode = findTreeNodes({ treeData: treeDataRef.current, keyValue: treeKeys })
            .reverse()
            .find((item) => !!item);

          if (thereNode || !treeDataRef.current?.length) {
            let loadKeys: string[];
            if (thereNode) {
              // 已经加载过数据,从加载的数据开始查找
              const index = treeKeys.findIndex((item) => item == thereNode.key);
              loadKeys = treeKeys.slice(index);
            } else {
              // 如果还没有加载过数据直接从根节点开始加载
              if (rootId) {
                const index = treeKeys.indexOf(rootId);
                loadKeys = treeKeys.slice(index);
              } else {
                loadKeys = treeKeys;
              }
            }
            for (let i = 0, len = loadKeys.length; i < len; i++) {
              const key = loadKeys[i];
              const nextKey = loadKeys[i + 1];

              const node = nextKey
                ? findTreeNode({ treeData: treeDataRef.current, keyValue: nextKey })
                : false;
              if (!node) {
                await getData({ key });
              }
              await new Promise((resolve) => setTimeout(resolve, 10));
            }
          } else {
            return Promise.reject('为找到树结构中的key');
          }
        }
        return true;
      } else {
        return Promise.reject('自动定义数据源，不支持自动加载远端数据');
      }
    },
    [fieldRelation, sourceModel, rootId],
  );

  useEffect(() => {
    if (props.value && props.sourcetype == 'model') {
      // value存在时，直接加载到存在的项
      getData({ key: rootId as string }).then(() => {
        loadOriginData(props.value).then(() => {
          emit?.('onload');
        });
      });
    } else {
      // 不存在时只加载顶层数据
      getData({ key: rootId as string }).then(() => {
        emit?.('onload');
        if ((!props.value || !props.value?.length) && expandNode) {
          // 默认展开
          setTimeout(() => {
            const key = treeDataRef.current?.[0]?.key;
            if (key) {
              $expandedKeys([key]);
            }
          }, 100);
        }
      });
    }
  }, []);

  useUpdateEffect(() => {
    if (props.value) {
      const values = Array.isArray(props.value) ? props.value : [props.value];
      const notLoad = values.filter(
        (value) => !treeListRef.current.find((item) => item.key == value),
      );

      if (notLoad?.length) {
        // 当数据不存在时，加载远端数据
        loadOriginData(notLoad);
      }
    }
  }, [props.value]);

  useImperativeHandle(
    ref,
    () => ({
      ...api(configEvents, {
        props,
        treeDataRef,
        $expandedKeys,
        $treeData,
        showTreeNameKey,
        treeNodeId,
        treeShowNodeId,
        treeNodeParentId,
        treeShowNodeParentId,
        loadOriginData,
        onChange,
      }),
    }),
    [props, fieldRelation, onChange],
  );

  const lazyLoadTreeData = async (node: LegacyDataNode) => {
    if (!node.children) {
      return getData(node as any);
    }
  };

  const IconsSettingsObj = useMemo(() => {
    if (IconsSettings?.config?.length) {
      const iconOptions = {};
      IconsSettings.config.forEach((item: any) => {
        if (item.iconTypeKey) {
          // @ts-ignore
          const field = IconsSettings['field'] as string;
          const iconField = field.indexOf('$') !== -1 ? field?.split('$')[1] : field;
          iconOptions[item.iconTypeKey] = item.defaultIcon;
          iconOptions[`${item.iconTypeKey}_expand`] = item.expandIcon;
          iconOptions['type'] = 'node';
          iconOptions['field'] = iconField;
        } else {
          iconOptions[item.iconType] = item.iconImg;
          iconOptions['type'] = 'normal';
        }
      });
      return iconOptions;
    } else {
      return {};
    }
  }, [IconsSettings?.config]);

  const onTreeExpand = useCallback((newExpandedKeys): void => {
    $expandedKeys(newExpandedKeys);
    emit?.('onTreeExpand', newExpandedKeys);
  }, []);

  const showTreeData = useMemo(() => {
    if (showIcon) {
      return treeDataLevelFormat({
        treeData,
        format: (item, parents) => {
          if (item.icon) {
            return {};
          }
          const level = parents.length + 1;
          let iconType: { type: string; color?: string };
          if (IconsSettingsObj['type'] == 'normal') {
            iconType =
              level == 1
                ? IconsSettingsObj['topIcon']
                  ? IconsSettingsObj['topIcon']
                  : expandedKeys.includes(item.key)
                    ? IconsSettingsObj['expandIcon']
                    : IconsSettingsObj['defaultIcon']
                : expandedKeys.includes(item.key)
                  ? IconsSettingsObj['expandIcon']
                  : IconsSettingsObj['defaultIcon'];
            if (!iconType) {
              iconType = IconsSettingsObj['defaultIcon'];
            }
          } else {
            iconType = IconsSettingsObj[item[IconsSettingsObj['field']] as string];
          }
          return {
            icon: iconType?.type ? (
              <InbizIcon type={iconType?.type} style={{ color: iconType.color }}></InbizIcon>
            ) : (
              <InbizIcon type={iconType as unknown as string}></InbizIcon>
            ),
          };
        },
      });
    } else {
      return treeData;
    }
  }, [treeData, showIcon, IconsSettingsObj, expandedKeys]);

  const handleDropdownVisibleChange = useCallback(
    (open) => {
      $dropDownOpen(open);
      emit?.('onDropdownVisibleChange', open);
      if (open) {
        const values = props.value
          ? Array.isArray(props.value)
            ? props.value
            : [props.value]
          : [];
        // 自动展开选择的项的父级
        if (values.length) {
          const parentKeys: string[] = [];
          values.forEach((key) => {
            const keys =
              findTreeParents({ treeData: treeDataRef.current, keyValue: key })?.map(
                (item) => item.key,
              ) || [];
            parentKeys.push(...keys);
          });
          $expandedKeys([...new Set(parentKeys)]);
        }
      }
    },
    [props.value, emit],
  );

  const handleChange = useCallback(
    (value) => {
      if (Array.isArray(value)) {
        onChange?.(value.map((item) => item.value));
      } else {
        onChange?.(value ? value : '');
      }
    },
    [onChange],
  );

  const showValue = useMemo(() => {
    const list = treeDataToArray(treeData);
    if (Array.isArray(props.value)) {
      const valueData = props.value
        .map((value) => {
          const data = list.find((listItem) => listItem.value == value);
          if (data) {
            return {
              label: data.title ?? data.label,
              value,
            };
          } else {
            return;
          }
        })
        .filter((item) => !!item);
      return valueData.length === props.value.length ? valueData : undefined;
    } else {
     const data= list.find((item) => {return item.value == props.value})
     let valueData=[]
     if(data){
       valueData.push({label:data.title??data.text,value:data.value})
     }
      return data ? valueData : undefined;
    }
  }, [props.value, treeData]);
  

 const text= useMemo(()=>{
  if (viewMode === 'look')  {
    const list = treeDataToArray(treeData);
    const value = Array.isArray(props.value) ? props.value : [props.value];
    return value.map(vItem => list.find((item) => (item.value == vItem))?.title).join(',');
  } else {
    return ''
  }
 },[viewMode, props.value, treeData])


  return (
    <div {...otherProps} style={{ width: '100%' }}>
      {viewMode=='look'?text:
            <AntdTreeSelect
            showArrow={true}
            suffixIcon={dropDownOpen ? <UpOutlined /> : <DownOutlined />}
            allowClear={allowClear}
            disabled={disabled || readOnly}
            value={showValue}
            onChange={handleChange}
            style={{ width: '100%' }}
            className={prefixCls}
            switcherIcon={
              <InbizIcon
                type="icon-tree-down"
                style={{ fontSize: 18, color: '#aaa', verticalAlign: 'text-bottom', paddingTop: '4px' }}
              />
            }
            treeCheckable={multiple}
            treeCheckStrictly={treeCheckStrictly}
            showSearch={false}
            showCheckedStrategy={SHOW_ALL}
            treeData={showTreeData}
            loadData={lazyLoadTreeData}
            treeExpandedKeys={expandedKeys}
            onDropdownVisibleChange={handleDropdownVisibleChange}
            onTreeExpand={onTreeExpand}
            onSelect={(value: string, node: object) => emit?.('onSelect', value, node)}
            listHeight={panelHeight > 0 ? panelHeight : undefined}
            treeIcon={showIcon && IconsSettings?.config?.length}
            dropdownClassName={prefixCls}
            placeholder={
              <span style={{ fontSize: 'var(--inbiz-font-size-base)' }}>
                <TextWidget>{placeholder}</TextWidget>
              </span>
            }
            notFoundContent={
              <Empty
                image={Empty.PRESENTED_IMAGE_SIMPLE}
                description={<TextWidget>TreeSelect.nodata</TextWidget>}
              />
            }
          />}

    </div>
  );
});

export default TreeSelect;
